package com.oss.service.oss;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oss.common.BaseResponse;
import com.oss.dto.oss.lastprice.*;
import com.oss.entity.oss.Instrument;
import com.oss.entity.oss.LastPrice;
import com.oss.enums.IsDeletedEnum;
import com.oss.mapper.oss.LastPriceMapper;
import com.oss.util.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chengqiang
 */
@Slf4j
@Service
public class LastPriceService extends ServiceImpl<LastPriceMapper, LastPrice> {
    @Autowired
    InstrumentService instrumentService;

    public IPage<LastPrice> selectByPage(PageDto dto){
        LambdaQueryWrapper<LastPrice> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(LastPrice::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(StringUtils.isNotBlank(dto.getInstrumentCode()),LastPrice::getInstrumentCode, dto.getInstrumentCode());
        lambdaQueryWrapper.eq(dto.getDate() != null,LastPrice::getDate, dto.getDate());
        lambdaQueryWrapper.orderByDesc(LastPrice::getCreateTime);
        return this.baseMapper.selectPage(new Page<>(dto.getPageNo(),dto.getPageSize()),lambdaQueryWrapper);
    }

    public String delete(String id) {
        LambdaUpdateWrapper<LastPrice> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(LastPrice::getId,id);
        updateWrapper.set(LastPrice::getIsDeleted,IsDeletedEnum.YES.getFlag());
        this.update(updateWrapper);
        return "操作成功";
    }

    /**
     * 根据日期+合约代码 统计数量
     * id不为空 , 排除次ID之外统计
     * @param instrumentCode
     * @param date
     * @return
     */
    public long countByDateAndCode(String instrumentCode,LocalDate date,String id){
        LambdaQueryWrapper<LastPrice> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(LastPrice::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(LastPrice::getInstrumentCode, instrumentCode);
        lambdaQueryWrapper.eq(LastPrice::getDate, date);
        if (StringUtils.isNotBlank(id)) {
            lambdaQueryWrapper.ne(LastPrice::getId, id);
        }
        return this.count(lambdaQueryWrapper);
    }

    public BaseResponse add(AddDto dto) {
        long count = countByDateAndCode(dto.getInstrumentCode(),dto.getDate(),null);
        if (count > 0){
            return BaseResponse.error("当前日期中已存在相同合约");
        } else {
            LastPrice entity = new LastPrice();
            BeanUtils.copyProperties(dto,entity);
            entity.setId(SnowFlakeUtil.getID());
            this.save(entity);
            return BaseResponse.success("操作成功");
        }
    }

    public BaseResponse updateData(UpdateDto dto) {
        long count = countByDateAndCode(dto.getInstrumentCode(),dto.getDate(),dto.getId());if (count > 0){
            return BaseResponse.error("当前日期中已存在相同合约");
        } else {
            LastPrice entity = new LastPrice();
            BeanUtils.copyProperties(dto,entity);
            this.updateById(entity);
            return BaseResponse.success("操作成功");
        }

    }

    /**
     * 通过合约代码和日期统计数量
     * @param instrumentCode    合约代码
     * @param date              日期
     * @return
     */
    public void deleteByInstrumentCodeAndDate(String instrumentCode, LocalDate date) {
        LambdaUpdateWrapper<LastPrice> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(LastPrice::getIsDeleted,IsDeletedEnum.NO.getFlag());
        wrapper.eq(LastPrice::getInstrumentCode,instrumentCode);
        wrapper.eq(LastPrice::getDate,date);
        wrapper.set(LastPrice::getIsDeleted,IsDeletedEnum.YES.getFlag());
        this.update(null,wrapper);
    }

    public String importData(ImportDataDto importDataDto) {
        List<LastPrice> addList = new ArrayList<>();
        log.info("导入行情数据="+ JSON.toJSONString(importDataDto));
        for (ImportDataDetailDto dto : importDataDto.getList() ) {
            deleteByInstrumentCodeAndDate(dto.getInstrumentID(),dto.getTradingDay());
            LastPrice entity = new LastPrice();
            entity.setInstrumentCode(dto.getInstrumentID());
            entity.setDate(dto.getTradingDay());
            entity.setLastPrice(dto.getLastPrice());
            entity.setOpenInterest(dto.getOpenInterest());
            entity.setTradeVolume(dto.getVolume());
            entity.setSettlementPrice(dto.getSettlementPrice());
            entity.setLimitUpPrice(dto.getUpperLimitPrice());
            entity.setLimitDownPrice(dto.getLowerLimitPrice());
            entity.setTopPrice(dto.getHighestPrice());
            entity.setBottomPrice(dto.getLowestPrice());
            entity.setId(SnowFlakeUtil.getID());
            entity.setCreatorId("-1");
            addList.add(entity);
        }
        if (CollectionUtils.isNotEmpty(addList)){
            this.saveBatch(addList);
        }
        return "操作成功";
    }

    /**
     * 根据交易合约代码获取最新价
     * 如果有最新价合约 , 使用此合约查询行情 , 只有二级和三级才有最新价合约
     * 如果交易合约对应合约表中的二级数据 , 只找二级的最新价合约
     * 如果交易合约对应合约表中的三级数据 , 只找三级的最新价合约 (不需要向上查找)
     * @param instrumentCodeSet
     * @return
     */
    public Map<String, BigDecimal> selectLastPriceByInstrumentCodeSet(Set<String> instrumentCodeSet) {
        Map<String, BigDecimal> returnMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){
            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.in(Instrument::getCode,instrumentCodeSet);
            lambdaQueryWrapper.in(Instrument::getLevel,Arrays.asList(2,3));
            List<Instrument> instrumentList = instrumentService.list(lambdaQueryWrapper);

            // key = 最新价合约 , value = 标的/期权合约代码    过滤掉最新价合约为空的
            Map<String,String> lastPriceCodeMap = instrumentList.stream().filter(item->StringUtils.isNotBlank(item.getLastPriceCode()))
                    .collect(Collectors.toMap(Instrument::getLastPriceCode,Instrument::getCode,(v1,v2) -> v2));
            // 将最新价合约加入合约列表, 查询他们的最新价
            instrumentCodeSet.addAll(lastPriceCodeMap.keySet());

            LambdaQueryWrapper<LastPrice> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(LastPrice::getIsDeleted,IsDeletedEnum.NO.getFlag());
            wrapper.in(LastPrice::getInstrumentCode,instrumentCodeSet);
            List<LastPrice> list = this.list(wrapper);
            // key=合约代码 , value=LastPrice
            Map<String, LastPrice> map = new HashMap<>();
            for (LastPrice lastPrice : list) {
                String instrumentCode = lastPrice.getInstrumentCode();
                // 如果当前合约已在map中 , 取出来比较一下日期, 存最新的日期对应的数据
                if (map.containsKey(instrumentCode)) {
                    LastPrice item = map.get(instrumentCode);
                    // 如果 当前的日期比map中存日期新 , 就替换
                    if (lastPrice.getDate().isAfter(item.getDate())) {
                        // 如果行情代码=最新价合约 , 返回时, key = 最新价合约对应的期权合约/标的合约 , value=取最新价合约对应的行情
                        map.put(lastPriceCodeMap.getOrDefault(lastPrice.getInstrumentCode(), instrumentCode), lastPrice);
                    }
                } else {
                    // 如果行情代码=最新价合约 , 返回时, value=取最新价合约对应的行情 , key = 最新价合约对应的期权合约/标的合约
                    map.put(lastPriceCodeMap.getOrDefault(lastPrice.getInstrumentCode(), instrumentCode), lastPrice);
                }
            }
            // 取出返回值
            for (Map.Entry<String, LastPrice> entry : map.entrySet()) {
                BigDecimal lastPrice = entry.getValue().getLastPrice();
                lastPrice = lastPrice == null ? BigDecimal.ZERO : lastPrice;
                returnMap.put(entry.getKey(),lastPrice);
            }
            return returnMap;
        } else {
            return new HashMap<>();
        }
    }
    /**
     * 根据历史持仓的合约代码对应的最新价
     * 如果有最新价合约 , 使用此合约查询行情 , 只有二级和三级才有最新价合约
     * 如果交易合约对应合约表中的二级数据 , 只找二级的最新价合约
     * 如果交易合约对应合约表中的三级数据 , 只找三级的最新价合约 (不需要向上查找)
     * @param instrumentCodeSet
     * @return
     */
    public Map<String, BigDecimal> selectHistoryLastPriceByInstrumentCodeSet(Set<String> instrumentCodeSet,LocalDate date) {
        Map<String, BigDecimal> returnMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){
            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.in(Instrument::getCode,instrumentCodeSet);
            lambdaQueryWrapper.in(Instrument::getLevel,Arrays.asList(2,3));
            List<Instrument> instrumentList = instrumentService.list(lambdaQueryWrapper);

            // key = 最新价合约 , value = 标的/期权合约代码    过滤掉最新价合约为空的
            Map<String,String> lastPriceCodeMap = instrumentList.stream().filter(item->StringUtils.isNotBlank(item.getLastPriceCode()))
                    .collect(Collectors.toMap(Instrument::getLastPriceCode,Instrument::getCode,(v1,v2) -> v2));
            // 将最新价合约加入合约列表, 查询他们的最新价
            instrumentCodeSet.addAll(lastPriceCodeMap.keySet());
            // 获取对应日期的历史持仓最新价
            LambdaQueryWrapper<LastPrice> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(LastPrice::getIsDeleted,IsDeletedEnum.NO.getFlag());
            wrapper.eq(LastPrice::getDate,date);
            wrapper.in(LastPrice::getInstrumentCode,instrumentCodeSet);
            List<LastPrice> list = this.list(wrapper);
            // key=合约代码 , value=LastPrice
            Map<String, LastPrice> map = new HashMap<>();
            for (LastPrice lastPrice : list) {
                String instrumentCode = lastPrice.getInstrumentCode();
                // 如果当前合约已在map中 , 取出来比较一下日期, 存最新的日期对应的数据
                if (map.containsKey(instrumentCode)) {
                    LastPrice item = map.get(instrumentCode);
                    // 如果 当前的日期比map中存日期新 , 就替换
                    if (lastPrice.getDate().isAfter(item.getDate())) {
                        // 如果行情代码=最新价合约 , 返回时, key = 最新价合约对应的期权合约/标的合约 , value=取最新价合约对应的行情
                        map.put(lastPriceCodeMap.getOrDefault(lastPrice.getInstrumentCode(), instrumentCode), lastPrice);
                    }
                } else {
                    // 如果行情代码=最新价合约 , 返回时, value=取最新价合约对应的行情 , key = 最新价合约对应的期权合约/标的合约
                    map.put(lastPriceCodeMap.getOrDefault(lastPrice.getInstrumentCode(), instrumentCode), lastPrice);
                }
            }
            // 取出返回值
            for (Map.Entry<String, LastPrice> entry : map.entrySet()) {
                BigDecimal lastPrice = entry.getValue().getLastPrice();
                lastPrice = lastPrice == null ? BigDecimal.ZERO : lastPrice;
                returnMap.put(entry.getKey(),lastPrice);
            }
            return returnMap;
        } else {
            return new HashMap<>();
        }
    }

    /**
     * 交易新增/ 修改时 ,根据合约代码查询最新价
     * @param underlyingCode
     * @return
     */
    public LastPrice getByUnderlyingCode(String underlyingCode) {
        LambdaQueryWrapper<LastPrice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LastPrice::getIsDeleted,IsDeletedEnum.NO.getFlag());
        wrapper.eq(LastPrice::getInstrumentCode,underlyingCode);
        wrapper.orderByDesc(LastPrice::getDate);
        wrapper.last("limit 1");
        return this.getOne(wrapper);
    }
}
